package cn.lds.j367.dsbank.aspect;

import cn.lds.j367.dsbank.common.dto.ResultDTO;
import cn.lds.j367.dsbank.controller.SyslogController;
import cn.lds.j367.dsbank.entity.Employee;
import cn.lds.j367.dsbank.entity.Syslog;
import cn.lds.j367.dsbank.service.impl.SyslogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.BindingResult;
import org.springframework.validation.support.BindingAwareModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Objects;
import java.util.stream.Stream;

@Component
@Aspect
public class SyslogAdvice{

    private Logger log = LoggerFactory.getLogger(SyslogAdvice.class);

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private SyslogService syslogService;

    private Date startTime;           //访问开始时间
    private Date endTIme;             //访问结束时间

    private Class visitClass;         //我们访问的Controller类的Class对象

    private Method visitMethod;        //访问的方法名

    //定义切入点表达式
    @Pointcut("execution(* cn.lds.j367.dsbank.controller.*.*(..))")
    private void pt(){}

    //前置增强
    @Before("pt()")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        startTime = new Date();
        //获取我们当前访问到的Controller类的Class对象
        visitClass = jp.getTarget().getClass();
        //获取访问方法的方法签名
        String methodName = jp.getSignature().getName();

        //获取请求方法中传递参数
        Object[] args = jp.getArgs();
        Stream.of(args).forEach(o -> {
            log.info("方法参数：{}", o);
        });
        if (Objects.isNull(args) || args.length == 0){
            //通过方法名获取方法对象
            visitMethod = visitClass.getMethod(methodName);
        }else {
            //定义一个方法，封装参数的Class对象
            Class[] classesArgs = new Class[args.length];
            for (int i = 0; i < args.length; i++) {

                if (args[i] instanceof BindingAwareModelMap){
                    classesArgs[i] = Model.class;
                    continue;
                }

                if (args[i] instanceof BeanPropertyBindingResult){
                    classesArgs[i] = BindingResult.class;
                    continue;
                }

                //将参数的Class对象存入Class数组
                classesArgs[i] = args[i].getClass();
            }
            //通过方法名和方法的参数获取方法对象
            visitMethod = visitClass.getMethod(methodName,classesArgs);
        }
        log.info("日志增强前置通知");
    }
    //后置增强
    @After("pt()")
    public void doAfter(){
        System.out.println(visitClass);
        log.info("日志增强后置方法");
        if (visitClass != SyslogController.class){
            //获取我们访问的类的RequestMapping注解对象
            RequestMapping classAnnotation = (RequestMapping) visitClass.getAnnotation(RequestMapping.class);


            if (classAnnotation !=null){
                //获取我们访问的方法的RequestMapping注解对象
                RequestMapping methodAnnotation = visitMethod.getAnnotation(RequestMapping.class);

                if (methodAnnotation != null){
                    String url = "";
                    //读取注解对象的注解元素的值，得到访问的url
                    url = classAnnotation.value()[0] + methodAnnotation.value()[0];

                    //封装数据
                    Syslog syslog = new Syslog();
                    //获取访问时长
                    Long visitTime = new Date().getTime() - startTime.getTime();
                    syslog.setVisitUrl(url);
                    syslog.setOperatorTime(startTime);
                    syslog.setVisitTime(visitTime);
                    //存入客户端IP地址
                    syslog.setIpAddress(request.getRemoteAddr());

                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

                    if (Objects.nonNull(authentication)){

                        //获取登录员工对象
                        Employee loginEmp = (Employee) authentication.getPrincipal();

                        syslog.setEmpId(loginEmp.getEmpId());

                        ResultDTO resultDTO = syslogService.addSyslog(syslog);

                        log.info("添加日志：{}",resultDTO);
                    }



                }
            }
        }
    }
}
